/*
	This file is part of AVRCppLib.

    AVRCppLib is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    AVRCppLib is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with AVRCppLib.  If not, see <http://www.gnu.org/licenses/>.

    Copyright (C) Maxime Lemonnier 2007-2011
 */


void USARTHardware::configureBitRate(uint16_t finePrescaler, bool doubleBitRate, bool synchroneous)
{
	#ifdef URSEL
	// USREL must be selected simultaneously with other bits since UCSRC shares IO address with UBRRH
	clearBit(*ucsrc, URSEL);
	#endif

	finePrescaler &= 0x0FFF;

	*ubrrl = (uint8_t)finePrescaler;
	*ubrrh = (uint8_t)(finePrescaler>>8);

	changeBitValueTo(*ucsra, U2X, doubleBitRate);

	changeBitValueTo(*ucsrc, UMSEL, synchroneous);
}

void USARTHardware::configureFrameSize(FrameSize dataBits)
{

	#ifdef URSEL
	// USREL must be selected simultaneously with other bits since UCSRC shares IO address with UBRRH
	setBit(*ucsrc, URSEL);
	#endif

	setConfig(ucsrc, buildMask(UCSZ0, UCSZ1), dataBits);

	changeBitValueTo(*ucsrb, UCSZ2, dataBits == FrameSizes::NINE_BITS);
}

void USARTHardware::configureStopBitsMode(StopBitsMode stopBits)
{

	#ifdef URSEL
	// USREL must be selected simultaneously with other bits since UCSRC shares IO address with UBRRH
	setBit(*ucsrc, URSEL);
	#endif

	setConfig(ucsrc, buildMask(USBS), stopBits);

}

void USARTHardware::configureParityMode(ParityMode parity)
{

	#ifdef URSEL
	// USREL must be selected simultaneously with other bits since UCSRC shares IO address with UBRRH
	setBit(*ucsrc, URSEL);
	#endif

	setConfig(ucsrc, buildMask(UPM0, UPM1), parity);

}

void USARTHardware::enableMPCM()
{
	setConfig(ucsra, buildMask(MPCM), 0x01);
}

void USARTHardware::disableMPCM()
{
	setConfig(ucsra, buildMask(MPCM), 0x00);
}

void USARTHardware::configureDefaults()
{
	configureBitRate();
	configureFrameSize();
	configureStopBitsMode();
	configureParityMode();
}

void USARTHardware::enableReceiver()
{
	setBit(*ucsrb, RXEN);
}

void USARTHardware::disableReceiver()
{
	clearBit(*ucsrb, RXEN);
}

void USARTHardware::enableFrameReceivedInterrupts()
{
	setBit(*ucsrb, RXCIE);
}

void USARTHardware::disableFrameReceivedInterrupts()
{
	clearBit(*ucsrb, RXCIE);
}

uint16_t USARTHardware::readFrame()
{

	if(bitIsSetInRegister(*ucsrb, RXB8))
		return *udr + USART_NINTH_BIT_MASK;

	return *udr;
}

bool USARTHardware::isFrameReceived()
{
	return bitIsSetInRegister(*ucsra, RXC);
}


void USARTHardware::clearFrameReceivedFlag()
{
	setBit(*ucsra, RXC);
}

void USARTHardware::enableTransmitter()
{
	setBit(*ucsrb, TXEN);
}

void USARTHardware::disableTransmitter()
{
	clearBit(*ucsrb, TXEN);
}

void USARTHardware::enableTransmitterReadyInterrupts()
{
	setBit(*ucsrb, UDRIE);
}

void USARTHardware::disableTransmitterReadyInterrupts()
{
	clearBit(*ucsrb, UDRIE);
}

void USARTHardware::writeFrame(uint16_t data)
{

	changeBitValueTo(*ucsrb, TXB8, data & USART_NINTH_BIT_MASK);

	*udr = (uint8_t)data;
}

bool USARTHardware::isTransmitterReady()
{
	return bitIsSetInRegister(*ucsra, UDRE);
}

bool USARTHardware::isFrameTransmitted()
{
	return bitIsSetInRegister(*ucsra, TXC);
}

void USARTHardware::clearFrameTransmittedFlag()
{
	setBit(*ucsra, TXC);
}

void USARTHardware::enableFrameTransmittedInterrupts()
{
	setBit(*ucsra, TXCIE);
}

void USARTHardware::disableFrameTransmittedInterrupts()
{
	clearBit(*ucsra, TXCIE);
}

uint8_t USARTHardware::status()
{
	return *ucsra & USART_UCSRA_STATUS_MASK;
}
